﻿using System;
using System.Collections.Generic;

namespace Framework
{

    /// <summary>
    /// 对象池负责将对象临时存储，以便销毁，
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObjectPool <T>  : IObjectPool where T : ObjectBase
    {
        // private Dictionary<Object, T> ObjectMap;

        /// <summary>
        /// 使用中的
        /// </summary>
        private List<T> usedObjects;
        /// <summary>
        /// 等待回收的
        /// </summary>
        private Dictionary<string, Queue<T>> waitToReleaseMap;
        
        /// <summary>
        /// 对象过期时间
        /// </summary>
        private float m_ExpireTime;
        
        private float m_AutoReleaseTime=0;
        /// <summary>
        /// 回收间隔
        /// </summary>
        private float m_AutoReleaseInterval=0;

        /// <summary>
        /// 获取对象池名称。
        /// </summary>
        public string Name
        {
            get;
            private set;
        }

        public ObjectPool(string name, float expireTime,float autoReleaseTime)
        {
            usedObjects = new List<T>();
            waitToReleaseMap=new Dictionary<string, Queue<T>>();
            m_ExpireTime = expireTime;
            m_AutoReleaseInterval = autoReleaseTime;
            Name = name;
        }
        /// <summary>
        /// 获取对象。
        /// </summary>
        /// <param name="name">对象名称。</param>
        /// <returns>要获取的对象。</returns>
        public T Spawn(string name)
        {
            if (name == null)
            {
                throw new GameFrameworkException("Name is invalid.");
            }

            if (waitToReleaseMap.ContainsKey(name))
            {
                if (waitToReleaseMap[name].Count > 0)
                {
                    return waitToReleaseMap[name].Dequeue();
                }
            }
            // GameFrameworkLinkedListRange<Object<T>> objectRange = default(GameFrameworkLinkedListRange<Object<T>>);
            // if (m_Objects.TryGetValue(name, out objectRange))
            // {
            //     foreach (Object<T> internalObject in objectRange)
            //     {
            //         if (m_AllowMultiSpawn || !internalObject.IsInUse)
            //         {
            //             return internalObject.Spawn();
            //         }
            //     }
            // }

            return null;
        }
        /// <summary>
        /// 回收对象。
        /// </summary>
        /// <param name="target">要回收的对象。</param>
        public void Unspawn(object target)
        {
            foreach (var objectBase in usedObjects.ToArray())
            {
                if (objectBase.Target == target)
                {
                    objectBase.LastUsedTime=DateTime.UtcNow;
                    usedObjects.Remove(objectBase);
                    AddToReleaseMap(objectBase);
                }
            }
        }
        /// <summary>
        /// 创建对象。
        /// </summary>
        /// <param name="obj">对象。</param>
        /// <param name="spawned">对象是否已被获取。</param>
        public void Register(T obj, bool spawned)
        {
            if (obj == null)
            {
                throw new GameFrameworkException("Object is invalid.");
            }

            if (spawned)
            {
                usedObjects.Add(obj);
            }
            else
            {
                AddToReleaseMap(obj);
            }
        }

        void AddToReleaseMap(T obj)
        {
            if (!waitToReleaseMap.ContainsKey(obj.Name))
            {
                waitToReleaseMap.TryAdd(obj.Name, new Queue<T>());
            }
            waitToReleaseMap[obj.Name].Enqueue(obj);
        }
        public void Release()
        {
            //遍历对象次，将需要释放的对象进行释放
           
            foreach (var kv in waitToReleaseMap)
            {
                foreach (var objectBase in kv.Value.ToArray())
                {
                    if (objectBase.LastUsedTime < DateTime.UtcNow.AddSeconds(-m_ExpireTime))
                    {
                        objectBase.Release(false);
                        kv.Value.Dequeue();
                    }
                }
            }
        }

        public void Update(float elapseSeconds, float realElapseSeconds)
        {
            m_AutoReleaseTime += realElapseSeconds;
            if (m_AutoReleaseTime < m_AutoReleaseInterval)
            {
                return;
            }
            m_AutoReleaseTime -= m_AutoReleaseInterval;
            Release();
        }
    }

}